package com.ustc.hewei.rpc.config;

import com.ustc.hewei.rpc.client.ClientProxyFactory;
import com.ustc.hewei.rpc.client.discovery.ServiceDiscovery;
import com.ustc.hewei.rpc.client.discovery.impl.RedisDiscovery;
import com.ustc.hewei.rpc.client.loadbalance.LoadBalanceChoose;
import com.ustc.hewei.rpc.client.loadbalance.ServiceGetter;
import com.ustc.hewei.rpc.client.loadbalance.UpdateService;
import com.ustc.hewei.rpc.client.loadbalance.impl.ConsistentHash;
import com.ustc.hewei.rpc.client.loadbalance.impl.RandomChoose;
import com.ustc.hewei.rpc.client.loadbalance.impl.RoundRobin;
import com.ustc.hewei.rpc.client.net.impl.NettyRpcClient;
import com.ustc.hewei.rpc.common.protocol.Service;
import com.ustc.hewei.rpc.propertise.RpcProperties;
import com.ustc.hewei.rpc.server.net.ChannelRequestHandler;
import com.ustc.hewei.rpc.server.net.NettyRpcServer;
import com.ustc.hewei.rpc.server.net.RequestHandler;
import com.ustc.hewei.rpc.server.net.RpcServer;
import com.ustc.hewei.rpc.server.register.RedisRegisterCenter;
import com.ustc.hewei.rpc.server.register.ServiceRegister;
import com.ustc.hewei.rpc.server.register.notify.NotifyRegister;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import static com.ustc.hewei.rpc.common.constant.LoadBalanceType.*;

/**
 * @author hewei
 * @version 1.0
 * @description: 自动注入bean的配置类
 * @date 2022/7/26 20:46
 */

@Configuration
public class AutoConfiguration {
    @Bean
    public DefaultRpcProcessor defaultRpcProcessor() {
        return new DefaultRpcProcessor();
    }

    @Bean
    public RpcProperties rpcProperties() {
        return new RpcProperties();
    }

    @Bean
    public ServiceRegister serviceRegister(@Autowired RpcProperties rpcProperties,
                                           @Autowired NotifyRegister notifyRegister) {
        return new RedisRegisterCenter(rpcProperties.getPort(), rpcProperties.getProtocol(), notifyRegister);
    }

    @Bean
    public RequestHandler requestHandler(@Autowired ServiceRegister serviceRegister) {
        return new RequestHandler(serviceRegister);
    }

    @Bean
    public RpcServer RpcServer(@Autowired RpcProperties rpcProperties) {
        return new NettyRpcServer(rpcProperties.getProtocol(), rpcProperties().getPort());
    }

    @Bean
    public ServiceDiscovery serviceDiscovery() {
        return new RedisDiscovery();
    }

    @Bean
    public NettyRpcClient nettyRpcClient() {
        return new NettyRpcClient();
    }

    @Bean
    public ClientProxyFactory clientProxyFactory(@Autowired NettyRpcClient rpcClient,
                                                 @Autowired ServiceGetter serviceGetter,
                                                 @Autowired RpcProperties properties) {
        return new ClientProxyFactory(rpcClient, serviceGetter, properties.getRetried());
    }

    @Bean
    public ChannelRequestHandler channelRequestHandler(@Autowired RequestHandler requestHandler) {
        return new ChannelRequestHandler(requestHandler);
    }

    @Bean
    public ConcurrentHashMap<String, List<Service>> cacheList() {
        return new ConcurrentHashMap<>();
    }

    @Bean
    public ServiceGetter serviceGetter(@Autowired ConcurrentHashMap<String, List<Service>> cacheList,
                                       @Autowired ServiceDiscovery serviceDiscovery,
                                       @Autowired RpcProperties properties,
                                       @Autowired LoadBalanceChoose loadBalanceChoose) {
        return new ServiceGetter(serviceDiscovery, cacheList, properties.getUpdateTime(), loadBalanceChoose);
    }

    @Bean
    public NotifyRegister notifyRegister(@Autowired RpcProperties properties) {
        return new NotifyRegister(properties.getRegisterCenterIp());
    }

    @Bean
    public LoadBalanceChoose loadBalanceChoose(@Autowired RpcProperties properties) {
        String strategy = properties.getLoadBalanceStrategy();
        LoadBalanceChoose res;
        switch (strategy) {
            case ROUND_ROBIN: {
                res = new RoundRobin();
                break;
            }
            case CONSISTENT_HASH: {
                res = new ConsistentHash();
                break;
            }
            case RANDOM: {
                res = new RandomChoose();
                break;
            }
            default:
                res = new RoundRobin();
        }
        return res;
    }

    @Bean
    public UpdateService updateService(@Autowired NotifyRegister notifyRegister,
                                       @Autowired ServiceGetter serviceGetter,
                                       @Autowired ConcurrentHashMap<String, List<Service>> cacheList,
                                       @Autowired ServiceDiscovery serviceDiscovery,
                                       @Autowired ClientProxyFactory clientProxyFactory) {
        return new UpdateService(notifyRegister, serviceGetter, serviceDiscovery, cacheList, clientProxyFactory);
    }
}
